﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Text.RegularExpressions;

using Idlesoft.Utils;


namespace Idlesoft.ShellAnywhereLanguage
{
	public class Param : TypeValue, IParam
	{
		static string CreateSig(string value = null)
		{
			return typeof(Param).ToString() + (!value.IsNullOrEmpty() ? value : "");
		}

		#region consts
		public const char NULL = '\0';
		#endregion consts

		#region ctors
		public Param(string value) : base (value) { }
		#endregion ctors

		#region props
		//[XmlIgnore]
		//public Type Type { get { return this.GetType(); } }
		//[XmlIgnore]
		//public TypeValue TypeValue { get { return new TypeValue(this.GetType(), Value); } }
		//[XmlAttribute]
		//public string Value { get; internal set; }
		[XmlIgnore]
		public int Length { get { return Value.Length; } }
		[XmlIgnore]
		public virtual LexemeType LexemeType { get { return LexemeType.Param; } }

		[XmlIgnore]
		public virtual string Sig { get { return Value + (char)LexemeType; } }

		[XmlIgnore]
		public Type[] Associations { get; set; }
		[XmlIgnore]
		public TypeValue[] Constraints { get; set; }
		#endregion props

		#region methods
		public bool Matches(string value)
		{
			return Regex.IsMatch(Value, "^" + value);
		}
		public virtual char CharAt(int dot)
		{
			char charAtDot = NULL;
			//if (0 <= dot && dot < Value.Length)
			if (IsValid(dot, false))
				charAtDot = Value[dot];
			return charAtDot;
		}
		public virtual string Matched(int dot)
		{
			string matched = "";
			//if (0 <= dot && dot <= Value.Length)
			if (IsValid(dot))
				matched = Value.Substring(0, dot);
			return matched;
		}
		public virtual string Unmatched(int dot)
		{
			string unmatched = "";
			//if (0 <= dot && dot <= Value.Length)
			if (IsValid(dot))
				unmatched = Value.Substring(dot, Value.Length - dot);
			return unmatched;
		}
		public virtual bool IsMatched(int dot)
		{
			return dot == Value.Length;
		}
		public virtual bool IsUnmatched(int dot)
		{
			return dot < Value.Length;
		}
		public virtual bool IsLast(int dot)
		{
			return (Value.Length - 1) - dot <= 0;
		}
		public virtual bool IsAssociatedWith<TItem>(TItem type = null)
			where TItem : class, IParam
		{
			return Associations != null && Associations.Any(association => typeof(TItem).IsType(association));
		}
		public virtual bool IsConstrainedBy<TItem>(TItem item) 
			where TItem : class, IParam
		{
			return Constraints != null && Constraints.Any(constraint => constraint.Type.IsType<TItem>() && constraint.Value.Equals(item.Value));
		}
		public override string ToString() { return Value; }
		public override int GetHashCode()
		{
			return base.GetHashCode() + Value.GetHashCode();
		}
		private bool IsValid(int dot, bool inclusive = true)
		{
			return 0 <= dot && dot <= (inclusive ? Value.Length : Value.Length - 1);
		}
		#endregion methods

		#region events
		public event Func<Type, bool> DoAssociatedWith;
		public event Func<TypeValue, bool> DoConstrainedBy;
		#endregion events

		#region fields
		#endregion fields
	}
}
